package com.vercer.engine.proxy;

import java.util.concurrent.Future;
import java.util.logging.Logger;

import com.google.appengine.api.quota.QuotaService;
import com.google.appengine.api.quota.QuotaServiceFactory;
import com.google.apphosting.api.ApiProxy.ApiConfig;
import com.google.apphosting.api.ApiProxy.ApiProxyException;
import com.google.apphosting.api.ApiProxy.Delegate;
import com.google.apphosting.api.ApiProxy.Environment;
import com.google.code.twig.util.FutureAdaptor;

public class LoggingApiProxyDelegate extends DelegatingApiProxy
{
	private static final Logger log = Logger.getLogger(LoggingApiProxyDelegate.class.getName());
	private QuotaService quotaService;

	public LoggingApiProxyDelegate(Delegate<Environment> delegate)
	{
		super(delegate);
		quotaService = QuotaServiceFactory.getQuotaService();
	}

	@Override
	public byte[] makeSyncCall(Environment arg0, String arg1, String arg2, byte[] arg3)
			throws ApiProxyException
	{
		long startWallClockTime = System.currentTimeMillis();
		long startApiTimeInMegaCycles = quotaService.getApiTimeInMegaCycles();
		long startCpuTimeInMegaCycles = quotaService.getCpuTimeInMegaCycles();
		
		byte[] result = super.makeSyncCall(arg0, arg1, arg2, arg3);
		
		long endApiTimeInMegaCycles = quotaService.getApiTimeInMegaCycles();
		long endCpuTimeInMegaCycles = quotaService.getCpuTimeInMegaCycles();
		long endWallClockTime = System.currentTimeMillis();
		
		int apiMs = (int) Math.round(quotaService.convertMegacyclesToCpuSeconds(endApiTimeInMegaCycles - startApiTimeInMegaCycles) * 1000);
		int cpuMs = (int) Math.round(quotaService.convertMegacyclesToCpuSeconds(endCpuTimeInMegaCycles - startCpuTimeInMegaCycles) * 1000);
		int ms = (int) (endWallClockTime - startWallClockTime);
		log.info(arg1 + " " + arg2 + " cpu_ms=" + cpuMs + " api_ms=" + apiMs + " ms=" + ms + "\n" + restrictLength(new String(arg3)));
		
		return result;
	}

	@Override
	public Future<byte[]> makeAsyncCall(Environment arg0, final String arg1, final String arg2, final byte[] arg3,
			ApiConfig arg4)
	{
		final long startWallClockTime = System.currentTimeMillis();
		final long startApiTimeInMegaCycles = quotaService.getApiTimeInMegaCycles();
		final long startCpuTimeInMegaCycles = quotaService.getCpuTimeInMegaCycles();
		
		Future<byte[]> result = super.makeAsyncCall(arg0, arg1, arg2, arg3, arg4);
		
		// make an adapter that will just log the timings and result the result
		result = new FutureAdaptor<byte[], byte[]>(result)
		{
			@Override
			protected byte[] adapt(byte[] source)
			{
				long endApiTimeInMegaCycles = quotaService.getApiTimeInMegaCycles();
				long endCpuTimeInMegaCycles = quotaService.getCpuTimeInMegaCycles();
				long endWallClockTime = System.currentTimeMillis();
				
				int apiMs = (int) Math.round(quotaService.convertMegacyclesToCpuSeconds(endApiTimeInMegaCycles - startApiTimeInMegaCycles) * 1000);
				int cpuMs = (int) Math.round(quotaService.convertMegacyclesToCpuSeconds(endCpuTimeInMegaCycles - startCpuTimeInMegaCycles) * 1000);
				final int ms = (int) (endWallClockTime - startWallClockTime);
				
				log.info(arg1 + " " + arg2 + " cpu_ms=" + cpuMs + " api_ms=" + apiMs + " ms=" + ms + ": " + restrictLength(new String(arg3)));
				return source;
			}
		};
		
		return result;
	}

	private String restrictLength(String string)
	{
		return string.length() < 100 ? string : string.substring(0, 100) + "...";
	}
}
